package org.kca.graphics;

import static org.lwjgl.opengl.GL11.*;

import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

/**
    Simple abstract class used for testing. Subclasses should
    implement the draw() method.
*/
public abstract class GameCore {

    protected static final int FONT_SIZE = 24;

    private static final int POSSIBLE_MODES[][] = {
        {1024, 768, 32},
    };

    private boolean isRunning;
    private int width, height;
    private final static TextureLoader loader = new TextureLoader();

    public GameCore()
    {
        init();
    }

    /**
        Sets full screen mode and initiates and objects.
    */
    public void init() {
        try
        {
    
            DisplayMode[] dms = Display.getAvailableDisplayModes();
            boolean found = false;
            for (int i = 0; i < POSSIBLE_MODES.length && !found; i++)
            {
                for (DisplayMode dm : dms)
                {
                    if (POSSIBLE_MODES[i][0] == dm.getWidth() &&
                            POSSIBLE_MODES[i][1] == dm.getHeight() &&
                            POSSIBLE_MODES[i][2] == dm.getBitsPerPixel())
                    {
                        Display.setDisplayMode(dm);
                        width = dm.getWidth();
                        height = dm.getHeight();
                        found = true;
                        break;
                    }
                }
            }
            
            Display.setFullscreen(true);
            Display.create();
            Display.setVSyncEnabled(true);
            glEnable(GL_TEXTURE_2D);
            glShadeModel(GL11.GL_SMOOTH);  
            // disable the OpenGL depth test since we're rendering 2D graphics
            glDisable(GL_DEPTH_TEST);
            glDisable(GL_LIGHTING);
            glEnable(GL11.GL_BLEND);
            glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(0, width, height, 0, -1, 1);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glViewport(0, 0, width, height);
            glClearColor(0, 0, 0, 0);
            glClearDepth(1);
            
        } 
        catch (LWJGLException e)
        {
            e.printStackTrace();
        }
    
    }

    /**
     * Gets the width in pixels of the full screen window
     * @return the screen width
     */
    public int getWidth()
    {
        return width;
    }
    
    /**
     * Gets the height in pixels of the full screen window
     * @return the screen height
     */
    public int getHeight()
    {
        return height;
    }


    /**
     *  Starts the game by calling gameLoop()
    */
    public void run() {
        try {
            isRunning = true;
            gameLoop();
        }
        finally {
            lazilyExit();
        }
    }

    /**
        Runs through the game loop until stop() is called.
    */
    public void gameLoop() {
        long time = getTime();

        while (isRunning) {
            long curTime = getTime();
            long elapsedTime = curTime - time;
            time = curTime;
            
            // update
            update(elapsedTime);
            // draw subcomponents
            glClear(GL_COLOR_BUFFER_BIT);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            draw();
            Display.update();
            Display.sync(60);
        }
        // clean up
        Display.destroy();
    }
    
    
    /**
        Signals the game loop that it's time to quit
    */
    public void stop() {
        isRunning = false;
    }

    /**
        Exits the VM from a daemon thread. The daemon thread waits
        2 seconds then calls System.exit(0). Since the VM should
        exit when only daemon threads are running, this makes sure
        System.exit(0) is only called if neccesary. It's neccesary
        if the Java Sound system is running.
    */
    public void lazilyExit() {
        Thread thread = new Thread() {
            public void run() {
                // first, wait for the VM exit on its own.
                try {
                    Thread.sleep(2000);
                }
                catch (InterruptedException ex) { }
                // system is still running, so force an exit
                System.exit(0);
            }
        };
        thread.setDaemon(true);
        thread.start();
    }

    /**
     * Get the high resolution time in milliseconds
     *
     * @return The high resolution time in milliseconds
     */
    public static long getTime() {
        // we get the "timer ticks" from the high resolution timer
        // multiply by 1000 so our end result is in milliseconds
        // then divide by the number of ticks in a second giving
        // us a nice clear time in milliseconds
        return (Sys.getTime() * 1000) / Sys.getTimerResolution();
    }
    
    /**
     * Gets the texture loader for this game
     * @return the texture loader
     */
    public static TextureLoader getTextureLoader()
    {
        return loader;
    }
    
    /**
        Updates the state of the game/animation based on the
        amount of elapsed time that has passed.
    */
    public abstract void update(long elapsedTime) ;


    /**
        Draws to the screen. Subclasses must override this
        method.
    */
    public abstract void draw();
}
